#!/usr / bin / env python3
# -*- coding: utf-8 -*-
"""
MySQL到KWDB数据迁移工具主程序

提供命令行接口，整合解析、转换、生成和验证功能。
"""

import os
import sys
import logging
import time
import yaml
# from pathlib import Path  # noqa: F401
from typing import Dict, Any, Optional

import click
from colorama import init, Fore, Style
# from tqdm import tqdm  # noqa: F401

try:
    # 尝试相对导入（当作为包使用时）
    from .parser import MySQLParser
    from .converter import MySQLToKWDBConverter
    from .generator import KWDBSQLGenerator
    from .validator import MigrationValidator
    from .stability import StabilityManager
    from .performance import PerformanceProfiler, performance_profiler
except ImportError:
    # 回退到绝对导入（当直接运行时）
    from parser import MySQLParser
    from converter import MySQLToKWDBConverter
    from generator import KWDBSQLGenerator
    from validator import MigrationValidator
    from stability import StabilityManager
    from performance import PerformanceProfiler, performance_profiler

# 初始化colorama
init()


class MigrationTool:
    """迁移工具主类"""

    def __init__(self, config: Optional[Dict[str, Any]] = None):
        self._config = config or {}
        self.setup_logging()

        self.parser = MySQLParser()
        self.converter = MySQLToKWDBConverter(config)
        self.generator = KWDBSQLGenerator(config)
        self.validator = MigrationValidator(config)
        self.stability_manager = StabilityManager()
        self.performance_profiler = PerformanceProfiler()

        self.logger = logging.getLogger(__name__)
        
        # 注册健康检查
        self._register_health_checks()

    @property
    def config(self):
        """获取配置"""
        return self._config

    def setup_logging(self):
        """设置日志"""
        log_config = self.config.get('logging', {})
        log_level = getattr(logging, log_config.get('level', 'INFO').upper())

        # 配置根日志器
        logging.basicConfig(
            level=log_level,
            format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
            handlers=[]
        )

        # 控制台输出
        if log_config.get('console', True):
            console_handler = logging.StreamHandler()
            console_handler.setLevel(log_level)
            formatter = logging.Formatter('%(levelname)s - %(message)s')
            console_handler.setFormatter(formatter)
            logging.getLogger().addHandler(console_handler)

        # 文件输出
        log_file = log_config.get('file')
        if log_file:
            file_handler = logging.FileHandler(log_file, encoding='utf-8')
            file_handler.setLevel(log_level)
            formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
            file_handler.setFormatter(formatter)
            logging.getLogger().addHandler(file_handler)

    def _register_health_checks(self):
        """注册健康检查"""
        # 文件系统健康检查
        def check_filesystem():
            import tempfile
            try:
                with tempfile.NamedTemporaryFile(delete=True) as f:
                    f.write(b"health_check")
                    f.flush()
                return True
            except Exception:
                return False
        
        # 内存健康检查
        def check_memory():
            try:
                import psutil
                memory = psutil.virtual_memory()
                return memory.available > 100 * 1024 * 1024  # 至少100MB可用
            except Exception:
                return True  # 如果无法检查，假设正常
        
        # 解析器健康检查
        def check_parser():
            try:
                test_sql = "CREATE TABLE test (id INT PRIMARY KEY);"
                result = self.parser.parse_content(test_sql)
                return len(result) > 0
            except Exception:
                return False
        
        self.stability_manager.register_health_check("filesystem", check_filesystem)
        self.stability_manager.register_health_check("memory", check_memory)
        self.stability_manager.register_health_check("parser", check_parser)

    def migrate(self,
                input_file: str,
                output_file: str,
                execute: bool = False,
                validate: bool = True,
                generate_reports: bool = True) -> bool:
        """
        执行完整的迁移流程

        Args:
            input_file: 输入的MySQL SQL文件
            output_file: 输出的KWDB SQL文件
            execute: 是否自动执行生成的SQL
            validate: 是否进行验证
            generate_reports: 是否生成报告

        Returns:
            是否成功
        """
        # 开始性能监控
        session_id = f"migration_{int(time.time())}"
        self.performance_profiler.start_session(session_id)
        
        try:
            # 启动稳定性管理
            self.stability_manager.start()
            
            # 运行健康检查
            health_status = self.stability_manager.run_health_checks()
            if health_status and not all(health_status.values()):
                self.print_warning(f"系统健康检查发现问题: {health_status}")
            
            self.print_header()

            # 1. 解析MySQL SQL文件（使用稳定性保障）
            self.print_step("解析MySQL SQL文件")
            original_statements = self.stability_manager.execute_with_stability(
                self.parser.parse_file,
                input_file,
                self.config.get('input', {}).get('encoding', 'utf-8')
            )

            if not original_statements:
                self.print_error("没有找到有效的SQL语句")
                return False

            self.print_success(f"成功解析{len(original_statements)}个语句")

            # 2. 转换语法（使用稳定性保障）
            self.print_step("转换MySQL语法到KWDB")
            converted_statements = self.stability_manager.execute_with_stability(
                self.converter.convert_statements, original_statements
            )

            _conversion_summary = self.converter.get_conversion_summary(
                original_statements, converted_statements
            )
            self.print_success(f"成功转换{len(converted_statements)}个语句")

            # 3. 生成KWDB SQL文件（使用稳定性保障）
            self.print_step("生成KWDB兼容SQL文件")
            success = self.stability_manager.execute_with_stability(
                self.generator.generate_sql_file,
                converted_statements,
                output_file,
                self.config.get('output', {}).get('encoding', 'utf-8')
            )

            if not success:
                self.print_error("生成SQL文件失败")
                return False

            self.print_success(f"成功生成SQL文件: {output_file}")

            # 4. 验证（使用稳定性保障，允许优雅降级）
            validation_results = []
            if validate:
                self.print_step("验证迁移结果")
                try:
                    validation_results = self.stability_manager.execute_with_stability(
                        self.validator.validate_migration,
                        original_statements,
                        converted_statements,
                        **self.config.get('kwdb', {})
                    )

                    failed_validations = [r for r in validation_results if not r.is_valid]
                    if failed_validations:
                        self.print_warning(f"验证发现{len(failed_validations)}个问题")
                    else:
                        self.print_success("验证通过")
                except Exception as e:
                    # 优雅降级：验证失败不中断迁移流程
                    self.print_warning(f"验证服务不可用，跳过验证步骤: {e}")
                    self.logger.warning(f"验证失败，但迁移继续: {e}")
                    validation_results = []  # 设置为空列表以避免后续错误

            # 5. 执行SQL（如果需要）
            if execute:
                self.print_step("执行SQL文件")
                success, stdout, stderr = self.generator.execute_sql_file(
                    output_file,
                    **self.config.get('kwdb', {})
                )

                if success:
                    self.print_success("SQL文件执行成功")
                else:
                    self.print_error(f"SQL文件执行失败: {stderr}")
                    return False

            # 6. 生成报告
            if generate_reports:
                self.print_step("生成迁移报告")

                # 生成迁移报告
                report_file = output_file.replace('.sql', '_migration_report.md')
                self.generator.generate_migration_report(
                    original_statements, converted_statements, report_file
                )

                # 生成验证报告
                if validate:
                    validation_report_file = output_file.replace('.sql', '_validation_report.md')
                    self.validator.generate_validation_report(
                        validation_results, validation_report_file
                    )

                # 生成回滚脚本
                rollback_file = output_file.replace('.sql', '_rollback.sql')
                self.generator.generate_rollback_script(converted_statements, rollback_file)

                self.print_success("报告生成完成")

            # 7. 生成性能报告
            self.performance_profiler.end_session(session_id)
            performance_report = self.performance_profiler.get_report(session_id)
            if performance_report:
                self.print_step("性能统计")
                self.print_success(f"总耗时: {performance_report.get('total_time', 0):.2f}秒")
                self.print_success(f"内存峰值: {performance_report.get('peak_memory', 0):.1f}MB")
                
                # 保存性能报告
                performance_file = output_file.replace('.sql', '_performance.json')
                try:
                    import json
                    with open(performance_file, 'w', encoding='utf-8') as f:
                        json.dump(performance_report, f, indent=2, ensure_ascii=False)
                    self.print_success(f"性能报告已保存: {performance_file}")
                except Exception as e:
                    self.print_warning(f"保存性能报告失败: {e}")

            self.print_header("迁移完成")
            return True

        except Exception as e:
            self.print_error(f"迁移过程中出错: {e}")
            self.logger.exception("迁移失败")
            return False
        finally:
            # 停止稳定性管理
            try:
                self.stability_manager.stop()
            except Exception as e:
                self.logger.warning(f"停止稳定性管理器时出错: {e}")
            
            # 确保性能监控会话结束
            try:
                if hasattr(self, 'performance_profiler'):
                    self.performance_profiler.end_session(session_id)
            except Exception as e:
                self.logger.warning(f"结束性能监控会话时出错: {e}")

    def print_header(self, title: str = "MySQL到KWDB迁移工具"):
        """打印标题"""
        print(f"\n{Fore.CYAN}{'='*60}")
        print(f"{title:^60}")
        print(f"{'='*60}{Style.RESET_ALL}\n")

    def print_step(self, message: str):
        """打印步骤信息"""
        print(f"{Fore.BLUE}[步骤] {message}...{Style.RESET_ALL}")

    def print_success(self, message: str):
        """打印成功信息"""
        print(f"{Fore.GREEN}[成功] {message}{Style.RESET_ALL}")

    def print_error(self, message: str):
        """打印错误信息"""
        print(f"{Fore.RED}[错误] {message}{Style.RESET_ALL}")

    def print_warning(self, message: str):
        """打印警告信息"""
        print(f"{Fore.YELLOW}[警告] {message}{Style.RESET_ALL}")


def load_config(config_file: str) -> Dict[str, Any]:
    """加载配置文件"""
    try:
        with open(config_file, 'r', encoding='utf-8') as f:
            return yaml.safe_load(f) or {}
    except Exception as e:
        click.echo(f"加载配置文件失败: {e}", err=True)
        return {}


@click.group()
@click.version_option(version="1.0.0")
def cli():
    """MySQL到KWDB数据迁移工具"""
    pass


@cli.command()
@click.option('--input', '-i', 'input_file', required=True,
              help='MySQL导出的SQL文件路径')
@click.option('--output', '-o', 'output_file', required=True,
              help='输出的KWDB SQL文件路径')
@click.option('--config', '-c', 'config_file',
              help='配置文件路径')
@click.option('--execute/--no - execute', default=False,
              help='是否自动执行生成的SQL文件')
@click.option('--validate/--no - validate', default=True,
              help='是否进行验证')
@click.option('--reports/--no - reports', default=True,
              help='是否生成报告')
@click.option('--kwbase-path', default='kwbase',
              help='kwbase CLI工具路径')
@click.option('--host', default='localhost',
              help='KWDB服务器地址')
@click.option('--port', default=26257, type=int,
              help='KWDB端口')
@click.option('--database', default='',
              help='目标数据库名')
@click.option('--insecure/--secure', default=True,
              help='是否使用非安全连接')
def migrate(input_file, output_file, config_file, execute, validate, reports,
            kwbase_path, host, port, database, insecure):
    """执行MySQL到KWDB的数据迁移"""

    # 检查输入文件
    if not os.path.exists(input_file):
        click.echo(f"输入文件不存在: {input_file}", err=True)
        sys.exit(1)

    # 加载配置
    config = {}
    if config_file:
        config = load_config(config_file)

    # 命令行参数覆盖配置文件
    config.setdefault('kwdb', {}).update({
        'kwbase_path': kwbase_path,
        'host': host,
        'port': port,
        'database': database,
        'insecure': insecure
    })

    # 创建迁移工具实例
    tool = MigrationTool(config)

    # 执行迁移
    success = tool.migrate(
        input_file=input_file,
        output_file=output_file,
        execute=execute,
        validate=validate,
        generate_reports=reports
    )

    if not success:
        sys.exit(1)


@cli.command()
@click.option('--input', '-i', 'input_file', required=True,
              help='MySQL导出的SQL文件路径')
@click.option('--config', '-c', 'config_file',
              help='配置文件路径')
def parse(input_file, config_file):
    """仅解析MySQL SQL文件，不进行转换"""

    if not os.path.exists(input_file):
        click.echo(f"输入文件不存在: {input_file}", err=True)
        sys.exit(1)

    _config = {}
    if config_file:
        _config = load_config(config_file)

    parser = MySQLParser()
    statements = parser.parse_file(input_file)

    click.echo(f"解析完成，共找到{len(statements)}个语句:")

    # 按类型统计
    type_counts = {}
    for stmt in statements:
        stmt_type = stmt.statement_type.value
        type_counts[stmt_type] = type_counts.get(stmt_type, 0) + 1

    for stmt_type, count in type_counts.items():
        click.echo(f"  {stmt_type}: {count}")

    # 显示表名
    table_names = parser.get_table_names()
    if table_names:
        click.echo(f"\n涉及的表 ({len(table_names)}个):")
        for table in sorted(table_names):
            click.echo(f"  - {table}")

    # 显示数据库名
    db_names = parser.get_database_names()
    if db_names:
        click.echo(f"\n涉及的数据库 ({len(db_names)}个):")
        for db in sorted(db_names):
            click.echo(f"  - {db}")


@cli.command()
@click.option('--sql-file', '-f', required=True,
              help='要执行的SQL文件路径')
@click.option('--kwbase-path', default='kwbase',
              help='kwbase CLI工具路径')
@click.option('--host', default='localhost',
              help='KWDB服务器地址')
@click.option('--port', default=26257, type=int,
              help='KWDB端口')
@click.option('--database', default='',
              help='目标数据库名')
@click.option('--insecure/--secure', default=True,
              help='是否使用非安全连接')
def execute(sql_file, kwbase_path, host, port, database, insecure):
    """执行SQL文件到KWDB"""

    if not os.path.exists(sql_file):
        click.echo(f"SQL文件不存在: {sql_file}", err=True)
        sys.exit(1)

    generator = KWDBSQLGenerator()

    click.echo(f"正在执行SQL文件: {sql_file}")

    success, stdout, stderr = generator.execute_sql_file(
        sql_file, kwbase_path, host, port, database, insecure
    )

    if success:
        click.echo("执行成功!")
        if stdout:
            click.echo("输出:")
            click.echo(stdout)
    else:
        click.echo("执行失败!", err=True)
        if stderr:
            click.echo("错误信息:", err=True)
            click.echo(stderr, err=True)
        sys.exit(1)


@cli.command()
@click.option('--template', '-t', default='basic',
              type=click.Choice(['basic', 'advanced']),
              help='配置模板类型')
@click.option('--output', '-o', default='config/config.yaml',
              help='配置文件输出路径')
def init_config(template, output):
    """生成配置文件模板"""

    # 确保输出目录存在
    output_dir = os.path.dirname(output)
    if output_dir:
        os.makedirs(output_dir, exist_ok=True)

    if template == 'basic':
        config_content = """# MySQL到KWDB迁移工具配置文件

# 输入输出配置
input:
  file: "mysql_dump.sql"
  encoding: "utf-8"

output:
  file: "kwdb_import.sql"
  encoding: "utf-8"

# KWDB连接配置
kwdb:
  kwbase_path: "kwbase"
  host: "localhost"
  port: 26257
  database: ""
  insecure: true

# 迁移选项
migration:
  execute: false
  batch_size: 1000
  skip_errors: false
  validate: true

# 日志配置
logging:
  level: "INFO"
  file: "migration.log"
  console: true
"""
    else:  # advanced
        # 使用完整的配置模板
        config_content = open('config/config.yaml', 'r', encoding='utf-8').read()

    with open(output, 'w', encoding='utf-8') as f:
        f.write(config_content)

    click.echo(f"配置文件已生成: {output}")


if __name__ == '__main__':
    cli()
